﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SoilProfiler
{



    public class ConfigurareTriangulation
    {
        private List<Triangulator.Geometry.TriangleId> triangles;
        private Columns columns;
        private List<Triangulator.Geometry.Point> Vertex;

        public List<Triangulator.Geometry.Point> VertexValue
        {
            get { return Vertex; }
            set { Vertex = value; }
        }
        public List<Volume> VolumeInfo;

             public ConfigurareTriangulation(Columns columns, List<Triangulator.Geometry.TriangleId> triangles, List<Triangulator.Geometry.Point> Vertex)
        {
            this.columns = columns;
            this.triangles = triangles;
            this.Vertex = Vertex;
        }
        public void Calculate()
        {

            List<Volume> volumeInfo = new List<Volume>();

            foreach (Triangulator.Geometry.TriangleId item in triangles)
            {
                List<IEnumerable<LayerColumn>> triangle = new List<IEnumerable<LayerColumn>>();
                Dictionary<int, Triangulator.Geometry.Point> vertex = new Dictionary<int, Triangulator.Geometry.Point>();

                triangle.Add
                ( columns.GetProfile(Vertex[item.triangle.p1].id));
                triangle.Add
                    (columns.GetProfile(Vertex[item.triangle.p2].id));
                triangle.Add
                   (columns.GetProfile(Vertex[item.triangle.p3].id));
                vertex.Add(item.triangle.p1,Vertex[item.triangle.p1]);
                vertex.Add(item.triangle.p2,Vertex[item.triangle.p2]);
                vertex.Add(item.triangle.p3,Vertex[item.triangle.p3]);

                volumeInfo.Add(new Volume(triangle,item.id,vertex));
                VolumeInfo = volumeInfo;

                
            }
        
        
        }


    }
    
    public class LayerTriangle3D
    {
        public  Triangulator.Geometry.Point3D[] vertex;
        public string Hguname {set; get;}
        public LayerTriangle3D( Triangulator.Geometry.Point3D[] vertex,   string hname)
        {
            this.vertex = vertex;
            this.Hguname = hname;

        }

        public double GetValue(double x, double y)
        { 
           Triangulator.Geometry.Point3D A=vertex[0];
            Triangulator.Geometry.Point3D B=vertex[1];
            Triangulator.Geometry.Point3D C=vertex[2];

            double a= (B.Y-A.Y) *(C.Z-A.Z) - (C.Y-A.Y)*(B.Z-A.Z);
            double b= (B.Z-A.Z) *(C.X-A.X) - (C.Z-A.Z)*(B.X-A.X);
            double c= (B.X-A.X) * (C.Y-A.Y)- (C.X-A.X)*(B.Y-A.Y);
            double d= -1*(a*A.X+b*A.Y+ c*A.Z);
            double value = (a * x + b * y + d) / (-1 * c);
            return value ;
        }
        

    }

    public class Volume
    {

        public List<LayerTriangle3D> Layers { set; get; }
        private List<IEnumerable<LayerColumn>> triangle;
        private Dictionary<int, Triangulator.Geometry.Point> vertex;
        public int id;
   

        public Volume(List<IEnumerable<LayerColumn>> triangle, int id, Dictionary<int, Triangulator.Geometry.Point> vertex)
        {
            this.triangle = triangle;
            this.id = id;
            this.vertex = vertex;
            int v = triangle[0].Count();
            compute();

        }

        private void compute()
        {   
           List<IEnumerable<LayerColumn>> triangle2 = new List<IEnumerable<LayerColumn>>();
           foreach (IEnumerable<LayerColumn> item in triangle)
           {


               triangle2.Add(OrderLayers(item));
           }
           triangle = triangle2;

           LinkData(triangle[0].ToList(), triangle[1].ToList(), triangle[2].ToList());

        }

        private void LinkData(List<LayerColumn> p1 ,List<LayerColumn> p2, List<LayerColumn> p3)
        {

            List<LayerTriangle3D> layers = new List<LayerTriangle3D>();
            LayerTriangle3D[] first = CreateFirstLayer(p1, p2, p3);

            layers.Add(first[0]);
           // layers[0].vertex[0].Point2D.id

            Evaluation(p1, p2, p3,ref layers);
            Evaluation(p1, p3, p2,ref layers);
            Evaluation(p2, p1, p3,ref layers);
            Evaluation(p2, p3, p1,ref layers);
            Evaluation(p3, p1, p2,ref layers);
            Evaluation(p3, p2, p1,ref layers);
            Layers = layers;
        }

        private void Evaluation(List<LayerColumn> p1, List<LayerColumn> p2, List<LayerColumn> p3, ref List<LayerTriangle3D> layers)
        {
            for (int i = 0; i < p1.Count; i++)
            {
                List<LayerColumn> dat1 = FindLayers(p1, p1[i].Unit);
                int maxp1=(from v in p1 select v.Order).Max();
                int maxp2=(from v in p2 select v.Order).Max();
                int maxp3=(from v in p3 select v.Order).Max();

                if (dat1.Count == 2 && dat1[0].Order < maxp1)
                {
                    List<LayerColumn> dat2 = FindLayers(p2, p1[i].Unit);
                    List<LayerColumn> dat3 = FindLayers(p3, p1[i].Unit);

                    if (dat2.Count == 2 && dat3.Count == 2)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[1].Profile, dat1[1].bottom, dat1[1].Id, dat1[1].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[1].Profile, dat2[1].bottom, dat2[1].Id, dat2[1].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[1].Profile, dat3[1].bottom, dat3[1].Id, dat3[1].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                            i++;
                        }

                    }


                    if (dat2.Count == 1 && dat3.Count == 1)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[1].Profile, dat1[1].bottom, dat1[1].Id, dat1[1].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                            i++;
                        }

                    }
                    if (dat2.Count == 2 && dat3.Count == 1)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[1].Profile, dat1[1].bottom, dat1[1].Id, dat1[1].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[1].bottom, dat2[1].Id, dat2[1].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                            i++;
                        }

                    }

                    if (dat2.Count == 1 && dat3.Count == 2)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[1].Profile, dat1[1].bottom, dat1[1].Id, dat1[1].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[1].bottom, dat3[1].Id, dat3[1].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                            i++;
                        }

                    }


                    if (dat2.Count == 1 && dat3.Count == 0 && dat2[0].Order == 0)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[1].Profile, dat1[1].bottom, dat1[1].Id, dat1[1].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(p3[0].Profile, p3[0].topelev, p3[0].Id, -1);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                        }
                    }

                    if (dat2.Count == 0 && dat3.Count == 1 && dat3[0].Order == 0)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[1].Profile, dat1[1].bottom, dat1[1].Id, dat1[1].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(p2[0].Profile, p2[0].topelev, p2[0].Id, -1);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                        }

                    }


                }












                if (dat1.Count == 1 && dat1[0].Order<maxp1)
                {
                    List<LayerColumn> dat2 = FindLayers(p2, p1[i].Unit);
                    List<LayerColumn> dat3 = FindLayers(p3, p1[i].Unit);
                    if (dat2.Count == 1 && dat3.Count == 1)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                        }

                    }
                    if (dat2.Count == 1 && dat3.Count == 0 && dat2[0].Order == 0)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(p3[0].Profile, p3[0].topelev, p3[0].Id, -1);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                        }
                    }

                    if (dat2.Count == 0 && dat3.Count == 1 && dat3[0].Order == 0)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(p2[0].Profile, p2[0].topelev, p2[0].Id, -1);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                        }

                    }


                    if (dat2.Count == 2 && dat3.Count == 1)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[1].Profile, dat2[1].bottom, dat2[1].Id, dat2[1].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                    
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);

                        }

                    }

                    if (dat2.Count == 1 && dat3.Count == 2)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[1].Profile, dat3[1].bottom, dat3[1].Id, dat3[1].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);

                        }

                    }



                }

                if (dat1.Count == 1 && dat1[0].Order == maxp1)
                {
                    List<LayerColumn> dat2 = FindLayers(p2, p1[i].Unit);
                    List<LayerColumn> dat3 = FindLayers(p3, p1[i].Unit);
                    if (dat2.Count == 1 && dat3.Count == 1)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                        }

                    }
                    if (dat2.Count == 1 && dat3.Count == 0 && dat2[0].Order <= maxp2)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(p3[maxp3].Profile, p3[maxp3].bottom, p3[maxp3].Id, maxp3);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                        }
                    }

                    if (dat2.Count == 0 && dat3.Count == 1 && dat3[0].Order <= maxp3)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(p2[maxp2].Profile, p2[maxp2].bottom, p2[maxp2].Id, maxp2);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                        }

                    }

                    if (dat2.Count == 2 && dat3.Count == 1)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[1].Profile, dat2[1].bottom, dat2[1].Id, dat2[1].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[0].Profile, dat3[0].bottom, dat3[0].Id, dat3[0].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                            
                        }

                    }

                    if (dat2.Count == 1 && dat3.Count == 2)
                    {
                        Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
                        Triangulator.Geometry.Point3D v1 = GetPointByHydroId(dat1[0].Profile, dat1[0].bottom, dat1[0].Id, dat1[0].Order);
                        Triangulator.Geometry.Point3D v2 = GetPointByHydroId(dat2[0].Profile, dat2[0].bottom, dat2[0].Id, dat2[0].Order);
                        Triangulator.Geometry.Point3D v3 = GetPointByHydroId(dat3[1].Profile, dat3[1].bottom, dat3[1].Id, dat3[1].Order);
                        data[0] = v1; data[1] = v2; data[2] = v3;
                        LayerTriangle3D value = new LayerTriangle3D(data, dat1[0].Unit);
                        if (!Exists(layers, value))
                        {
                            layers.Add(value);
                           
                        }

                    }


                }





            }
        }

        private bool Exists(List<LayerTriangle3D> layers, LayerTriangle3D value)
        {
            int i=0;
            foreach (LayerTriangle3D item in layers)
            {
                if (i != 0)
                {
                    int v=0;
                    foreach (Triangulator.Geometry.Point3D item2 in item.vertex)
                    {
                        if (item2.BoreholeId == value.vertex[0].BoreholeId)
                            v++;
                        if (item2.BoreholeId == value.vertex[1].BoreholeId)
                            v++;
                        if (item2.BoreholeId == value.vertex[2].BoreholeId)
                            v++;
                    }
                    if (v == 3)
                    { return true; }
                  
                    v=0;
                      
                }
                        
                        i++;
            }
            return false;
        }


        private Triangulator.Geometry.Point3D GetPointByHydroId(int id,double z, int boreId, int order)
        {

            Triangulator.Geometry.Point po= (from i in vertex where i.Value.id ==id select i.Value).ToArray()[0];

            Triangulator.Geometry.Point3D p=new Triangulator.Geometry.Point3D(po, z);
            p.BoreholeId = boreId;
            p.OrderBorehole = order;
            return p;
        }

        private LayerTriangle3D[] CreateFirstLayer(List<LayerColumn> p1, List<LayerColumn> p2, List<LayerColumn> p3)
        {
            List<LayerTriangle3D> layer = new List<LayerTriangle3D>();
             string n1=p1[0].Unit;
             string n2 = p2[0].Unit;
            string n3 = p1[0].Unit;
            Triangulator.Geometry.Point3D[] data = new Triangulator.Geometry.Point3D[3];
            Triangulator.Geometry.Point3D v1 = GetPointByHydroId(p1[0].Profile, p1[0].topelev,p1[0].Id,-1);
            Triangulator.Geometry.Point3D v2 = GetPointByHydroId(p2[0].Profile, p2[0].topelev,p2[0].Id,-1);
            Triangulator.Geometry.Point3D v3 = GetPointByHydroId(p3[0].Profile, p3[0].topelev,p3[0].Id,-1);
            data[0] = v1;
            data[1] = v2;
            data[2] = v3;

            if (n1 == n2 && n1 == n3)
            { 
              layer.Add(new LayerTriangle3D(data, n1));
            }
            if (n1 == n2 && n1 != n3)
            {
                layer.Add(new LayerTriangle3D(data, n1));
            }
            if (n1 == n3 && n1 != n2)
            {
                layer.Add(new LayerTriangle3D(data, n1));
            }
            if (n1 != n3 && n1 != n2)
            {
                layer.Add(new LayerTriangle3D(data, "To Divide"));
            }

            return layer.ToArray();


        }


        private List<LayerColumn> FindLayers(List<LayerColumn> data, string name)
        {

            IEnumerable<LayerColumn> list = from i in data where i.Unit == name select i;
            return list.ToList();
        }

        private List<LayerColumn> OrderLayers(IEnumerable<LayerColumn> layers)
        {

            List<LayerColumn> lista = new List<LayerColumn>();
            List<LayerColumn> list = layers.OrderBy(p => p.topelev).Reverse().ToList();
            for (int i = 0; i <  list.Count; i++)
            {
                list[i].Order=i;
                lista.Add(list[i]);
                
            }

            return lista;
            
        
        }


    }
}
